/*     */ package com.zimbra.cs.octosync;
/*     */ 
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.LogFactory;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.mailbox.OperationContext;
/*     */ import java.io.ByteArrayInputStream;
/*     */ import java.io.DataInputStream;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import java.io.OutputStream;
/*     */ import java.security.MessageDigest;
/*     */ import java.security.NoSuchAlgorithmException;
/*     */ import java.util.Arrays;
/*     */ import org.apache.commons.codec.binary.Hex;
/*     */ import org.apache.commons.io.input.TeeInputStream;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class PatchInputStream
/*     */   extends InputStream
/*     */ {
/*  55 */   private static final Log log = LogFactory.getLog(PatchInputStream.class);
/*     */   
/*     */ 
/*     */ 
/*     */   private static final int MAX_REF_LENGTH = 65536;
/*     */   
/*     */ 
/*     */ 
/*     */   private PatchReader patchReader;
/*     */   
/*     */ 
/*     */   private BlobAccess blobAccess;
/*     */   
/*     */ 
/*     */   private PatchManifest manifest;
/*     */   
/*     */ 
/*     */   private InputStream currentIs;
/*     */   
/*     */ 
/*     */ 
/*     */   public PatchInputStream(PatchReader patchReader, BlobAccess blobAccess, PatchManifest manifest)
/*     */     throws IOException, ServiceException
/*     */   {
/*  79 */     this.patchReader = patchReader;
/*  80 */     this.blobAccess = blobAccess;
/*  81 */     this.manifest = manifest;
/*  82 */     this.currentIs = nextInputStream();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static PatchInputStream create(InputStream is, Mailbox mbox, OperationContext opContext, int defaultFileId, int defaultVersion, OutputStream patchOs, PatchManifest manifest)
/*     */     throws IOException, ServiceException
/*     */   {
/* 108 */     InputStream input = null;
/*     */     
/* 110 */     if (patchOs != null) {
/* 111 */       input = new TeeInputStream(is, patchOs);
/*     */     } else {
/* 113 */       input = is;
/*     */     }
/*     */     
/* 116 */     return new PatchInputStream(new BinaryPatchReader(input), new BlobAccessViaMailbox(mbox, opContext, defaultFileId, defaultVersion), manifest);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   private InputStream nextInputStream()
/*     */     throws IOException, ServiceException
/*     */   {
/* 124 */     if (!this.patchReader.hasMoreRecordInfos()) {
/* 125 */       return null;
/*     */     }
/*     */     
/* 128 */     PatchReader.RecordInfo ri = this.patchReader.getNextRecordInfo();
/*     */     
/* 130 */     InputStream nextStream = null;
/*     */     
/* 132 */     if (ri.type == PatchReader.RecordType.DATA)
/*     */     {
/* 134 */       log.debug("Patch data, length: " + ri.length);
/* 135 */       nextStream = this.patchReader.popData();
/*     */     }
/* 137 */     else if (ri.type == PatchReader.RecordType.REF)
/*     */     {
/* 139 */       PatchRef patchRef = this.patchReader.popRef();
/* 140 */       log.debug("Patch reference " + patchRef);
/*     */       
/* 142 */       if (patchRef.length > 65536) {
/* 143 */         throw new InvalidPatchReferenceException("referenced data too large: " + patchRef.length + " > " + 65536);
/*     */       }
/*     */       
/*     */ 
/* 147 */       if (this.manifest != null) {
/* 148 */         int[] actualRef = this.blobAccess.getActualReference(patchRef.fileId, patchRef.fileVersion);
/* 149 */         this.manifest.addReference(actualRef[0], actualRef[1], patchRef.length);
/*     */       }
/*     */       try
/*     */       {
/* 153 */         InputStream blobIs = this.blobAccess.getBlobInputStream(patchRef.fileId, patchRef.fileVersion);
/*     */         
/*     */ 
/* 156 */         blobIs.skip(patchRef.offset);
/*     */         
/* 158 */         byte[] chunkBuf = new byte[patchRef.length];
/*     */         
/* 160 */         DataInputStream dis = new DataInputStream(blobIs);
/* 161 */         dis.readFully(chunkBuf);
/* 162 */         dis.close();
/*     */         
/* 164 */         MessageDigest md = MessageDigest.getInstance("SHA-256");
/* 165 */         md.update(chunkBuf);
/* 166 */         byte[] calcHash = md.digest();
/*     */         
/* 168 */         if (!Arrays.equals(patchRef.hashKey, calcHash)) {
/* 169 */           throw new InvalidPatchReferenceException("refrenced data hash mismatch, actual hash: " + new String(Hex.encodeHex(calcHash)) + "; " + patchRef);
/*     */         }
/*     */         
/*     */ 
/* 173 */         nextStream = new ByteArrayInputStream(chunkBuf);
/*     */       }
/*     */       catch (NoSuchAlgorithmException e) {
/* 176 */         e.printStackTrace();
/* 177 */         if (!$assertionsDisabled) throw new AssertionError("SHA-256 must be supported");
/*     */       }
/*     */     }
/* 180 */     else if (!$assertionsDisabled) { throw new AssertionError("Invalid record type: " + ri.type);
/*     */     }
/*     */     
/* 183 */     assert (nextStream != null) : "Stream returned here must be non-null";
/* 184 */     return nextStream;
/*     */   }
/*     */   
/*     */   public int read(byte[] b, int off, int len)
/*     */     throws IOException
/*     */   {
/* 190 */     if (this.currentIs == null) {
/* 191 */       return -1;
/*     */     }
/*     */     
/* 194 */     int result = this.currentIs.read(b, off, len);
/*     */     
/* 196 */     if (result == -1)
/*     */     {
/* 198 */       this.currentIs.close();
/*     */       
/*     */       try
/*     */       {
/* 202 */         this.currentIs = nextInputStream();
/*     */       } catch (ServiceException e) {
/* 204 */         throw new PatchException(e);
/*     */       }
/* 206 */       if (this.currentIs != null) {
/* 207 */         result = this.currentIs.read(b, off, len);
/*     */       }
/*     */     }
/* 210 */     return result;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public int read()
/*     */     throws IOException
/*     */   {
/* 219 */     byte[] buf = new byte[1];
/* 220 */     int result = read(buf, 0, 1);
/* 221 */     if (result == 1) {
/* 222 */       return buf[0];
/*     */     }
/* 224 */     return result;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public int available()
/*     */     throws IOException
/*     */   {
/* 233 */     if (this.currentIs != null) {
/* 234 */       return this.currentIs.available();
/*     */     }
/* 236 */     return 0;
/*     */   }
/*     */   
/*     */   public void close()
/*     */     throws IOException
/*     */   {
/*     */     try
/*     */     {
/* 244 */       super.close();
/*     */     } finally {
/* 246 */       this.patchReader.close();
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/octosync/PatchInputStream.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */